package com.xyzboom.compiler.compiler.lexer

import com.xyzboom.compiler.util.lineIndexThatIndexOf
import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

/**
 * Parse code
 *
 * @param code code string
 * @param lexerRules
 * @return tokens
 */
fun parseCode(code: String, lexerRules: List<LexerRule>): List<Token?> {
    val result = ArrayList<Token?>()
    val codeCharList = code.toList()
    var i = 0
    while (true) {
        var tryParseEndIndex: Int = i
        val lexerRule = lexerRules.filter { it.typeName != "NONE" }.find {
            tryParseEndIndex = it.dfa.acceptFrom(i, codeCharList, it.greedy)
            tryParseEndIndex > i
        }
        if (lexerRule == null) {
            val (lineIndex, indexInLine) = code.lineIndexThatIndexOf(i)
            logger.warn {
                "WARNING: Unknown char ${code[i]} at line ${lineIndex}:${indexInLine}"
            }
            i++
            if (i >= code.length) break
            continue
        }
        val (lineIndex, indexInLine) = code.lineIndexThatIndexOf(i + 1)
        val subEnd = if (tryParseEndIndex > code.length) {
            code.length
        } else tryParseEndIndex
        result.add(
            Token(
                lexerRule.name, lexerRule.typeName,
                code.substring(i, subEnd), lineIndex,
                indexInLine
            )
        )
        i = tryParseEndIndex
        if (i >= code.length) break
    }
    return result
}